/*
  Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
 */

#ifndef OT_BUFFER_DETAIL_H
#define OT_BUFFER_DETAIL_H

#include "securec.h"
#ifdef __KERNEL__
#include "ot_osal.h"
#endif
#include "ot_type.h"
#include "ot_common.h"
#include "ot_common_video.h"
#include "ot_math.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define OT_MAXI_NUM_LIMIT 30000

#define OT_SEG_RATIO_8BIT_LUMA      1300
#define OT_SEG_RATIO_8BIT_CHROMA    2000

#define OT_SEG_WIDTH_BIT_ALIGN 128
#define OT_FMU_MIN_BUF_LINE    32

static td_void ot_common_get_pic_buf_cfg(const ot_pic_buf_attr *buf_attr, ot_vb_calc_cfg *calc_cfg);

__inline static td_void ot_common_get_fmap_compress_buf_cfg(const ot_pic_buf_attr *buf_attr, ot_vb_calc_cfg *calc_cfg)
{
    td_u32 chn_num;
    td_u32 width, height;
    td_u32 main_stride, main_size, y_size, c_size;

    if (calc_cfg == TD_NULL) {
        return;
    }
    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    if (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_400) {
        chn_num = 4; /* 4 chn */
        width = buf_attr->width;
        height = buf_attr->height;
    } else if ((buf_attr->pixel_format >= OT_PIXEL_FORMAT_RGB_BAYER_8BPP) &&
               (buf_attr->pixel_format <= OT_PIXEL_FORMAT_RGB_BAYER_16BPP)) {
        chn_num = 8; /* 8 chn */
        width = buf_attr->width / 4;
        height = buf_attr->height;
    } else if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420) ||
               (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420)) {
        chn_num = 4; /* 4 chn */
        width = buf_attr->width / 4;
        height = buf_attr->height;
    } else { /* RGB */
        chn_num = 8; /* 8 chn */
        width = buf_attr->width / 2;
        height = buf_attr->height;
    }

    main_stride = 24 + chn_num * OT_DIV_UP(width, 32) + chn_num * width * 8 + (chn_num / 2) * 64;
    main_stride = OT_DIV_UP(main_stride, 128) * 16;

    y_size = main_stride * height;
    if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420)) {
        c_size = y_size / 2;
    } else {
        c_size = 0;
    }
    main_size = y_size + c_size;

    calc_cfg->vb_size = main_size;
    calc_cfg->head_stride = 0;
    calc_cfg->head_size = 0;
    calc_cfg->head_y_size = 0;
    calc_cfg->main_stride = main_stride;
    calc_cfg->main_size = main_size;
    calc_cfg->main_y_size = y_size;
}

__inline static td_void ot_common_get_tile32x4_yuv_buf_cfg(const ot_pic_buf_attr *buf_attr, ot_vb_calc_cfg *calc_cfg)
{
    td_u32 width, height;

    if (calc_cfg == TD_NULL) {
        return;
    }

    (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));

    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        return;
    }

    width = buf_attr->width;
    height = buf_attr->height;

    calc_cfg->main_stride = OT_ALIGN_UP(width, 32);
    if (buf_attr->compress_mode == OT_COMPRESS_MODE_NONE) {
        calc_cfg->vb_size = calc_cfg->main_stride * OT_ALIGN_UP(height, 4) * 2;
        return;
    }

    calc_cfg->vb_size = calc_cfg->main_stride * OT_ALIGN_UP(height, 4);
}

__inline static td_bool ot_common_is_pixel_format_rgb_bayer(ot_pixel_format pixel_format)
{
    if ((pixel_format == OT_PIXEL_FORMAT_RGB_BAYER_8BPP) || (pixel_format == OT_PIXEL_FORMAT_RGB_BAYER_10BPP) ||
        (pixel_format == OT_PIXEL_FORMAT_RGB_BAYER_12BPP) || (pixel_format == OT_PIXEL_FORMAT_RGB_BAYER_14BPP) ||
        (pixel_format == OT_PIXEL_FORMAT_RGB_BAYER_16BPP)) {
        return TD_TRUE;
    }
    return TD_FALSE;
}

__inline static td_u32 ot_common_get_bit_width(ot_data_bit_width bit_width)
{
    switch (bit_width) {
        case OT_DATA_BIT_WIDTH_8:
            return 8;
        case OT_DATA_BIT_WIDTH_10:
            return 10;
        case OT_DATA_BIT_WIDTH_12:
            return 12;
        case OT_DATA_BIT_WIDTH_14:
            return 14;
        case OT_DATA_BIT_WIDTH_16:
            return 16;
        case OT_DATA_BIT_WIDTH_32:
            return 32;
        case OT_DATA_BIT_WIDTH_64:
            return 64;
        default:
            return 0;
    }
}

__inline static td_u32 ot_vi_get_raw_bit_width(ot_pixel_format pixel_format)
{
    switch (pixel_format) {
        case OT_PIXEL_FORMAT_RGB_BAYER_8BPP:
            return 8; /* 8:single pixel width */
        case OT_PIXEL_FORMAT_RGB_BAYER_10BPP:
            return 10; /* 10:single pixel width */
        case OT_PIXEL_FORMAT_RGB_BAYER_12BPP:
            return 12; /* 12:single pixel width */
        case OT_PIXEL_FORMAT_RGB_BAYER_14BPP:
            return 14; /* 14:single pixel width */
        case OT_PIXEL_FORMAT_RGB_BAYER_16BPP:
            return 16; /* 16:single pixel width */
        default:
            return 0;
    }
}

__inline static td_u32 ot_common_get_valid_align(td_u32 align)
{
    /* align: 0 is automatic mode, alignment size following system. Non-0 for specified alignment size */
    if (align == 0) {
        return OT_DEFAULT_ALIGN;
    } else if (align > OT_MAX_ALIGN) {
        return OT_MAX_ALIGN;
    } else {
        return OT_ALIGN_UP(align, OT_DEFAULT_ALIGN);
    }
}

__inline static td_void ot_common_get_raw_buf_cfg_with_compress_ratio(const ot_pic_buf_attr *buf_attr,
    td_u32 compress_ratio, ot_vb_calc_cfg *calc_cfg)
{
    td_u32 width, height, bit_width;
    td_u32 align;
    td_u32 stride = 0;
    td_u32 size = 0;
    td_u32 raw_compress_ratio;

    if (calc_cfg == TD_NULL) {
        return;
    }
    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    width = buf_attr->width;
    height = buf_attr->height;
    bit_width = ot_vi_get_raw_bit_width(buf_attr->pixel_format);
    align = ot_common_get_valid_align(buf_attr->align);

    if (buf_attr->compress_mode == OT_COMPRESS_MODE_NONE) {
        stride = OT_ALIGN_UP(OT_ALIGN_UP(width * bit_width, 8) / 8, align);
        size = stride * height;
    } else if (buf_attr->compress_mode == OT_COMPRESS_MODE_LINE) {
        if ((OT_DIV_UP(width, 32) * height) <= 4096) {
            stride = (16 + width * bit_width + (width + 31) / 32 + 127) / 128;
        } else {
            raw_compress_ratio = 1538;
            stride = (width * bit_width * 1000UL / raw_compress_ratio + 8192 + 127) / 128;
        }
        stride = OT_ALIGN_UP(OT_ALIGN_UP(stride, 2) * 16, align);
        size = stride * height;
    } else if (buf_attr->compress_mode == OT_COMPRESS_MODE_FRAME) {
        if ((OT_DIV_UP(width, 32) * height) <= 4096) {
            size = (height * width * bit_width * 3 / 2 + (width + 31) / 32 * height + 255) / 256 * 2 * 16;
        } else {
            raw_compress_ratio = (compress_ratio == 0) ? 2000 : compress_ratio;
            size = (height * width * bit_width * 1000UL / raw_compress_ratio + 255) / 256 * 2 * 16;
        }
        size = OT_ALIGN_UP(size, align);
    } else { /* not support */
    }

    calc_cfg->vb_size     = size;
    calc_cfg->head_stride = 0;
    calc_cfg->head_size   = 0;
    calc_cfg->head_y_size = 0;
    calc_cfg->main_stride = stride;
    calc_cfg->main_size   = size;
    calc_cfg->main_y_size = size;
}

__inline static td_void ot_common_get_raw_buf_cfg(const ot_pic_buf_attr *buf_attr, ot_vb_calc_cfg *calc_cfg)
{
    /* use default frame compress ratio */
    ot_common_get_raw_buf_cfg_with_compress_ratio(buf_attr, 0, calc_cfg);
}

__inline static td_bool ot_common_is_pixel_format_package_422(ot_pixel_format pixel_format)
{
    if ((pixel_format == OT_PIXEL_FORMAT_YUYV_PACKAGE_422) || (pixel_format == OT_PIXEL_FORMAT_YVYU_PACKAGE_422) ||
        (pixel_format == OT_PIXEL_FORMAT_UYVY_PACKAGE_422) || (pixel_format == OT_PIXEL_FORMAT_VYUY_PACKAGE_422) ||
        (pixel_format == OT_PIXEL_FORMAT_YYUV_PACKAGE_422) || (pixel_format == OT_PIXEL_FORMAT_YYVU_PACKAGE_422) ||
        (pixel_format == OT_PIXEL_FORMAT_UVYY_PACKAGE_422) || (pixel_format == OT_PIXEL_FORMAT_VUYY_PACKAGE_422) ||
        (pixel_format == OT_PIXEL_FORMAT_VY1UY0_PACKAGE_422)) {
        return TD_TRUE;
    }
    return TD_FALSE;
}

__inline static td_void ot_common_get_uncompressed_yuv_buf_cfg(const ot_pic_buf_attr *buf_attr,
    ot_vb_calc_cfg *calc_cfg)
{
    td_u32 align_height, bit_width, size, y_size;
    td_u32 align, stride;

    if (calc_cfg == TD_NULL) {
        return;
    }
    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    align_height = OT_ALIGN_UP(buf_attr->height, 2);
    bit_width = ot_common_get_bit_width(buf_attr->bit_width);
    align = ot_common_get_valid_align(buf_attr->align);

    stride = OT_ALIGN_UP((buf_attr->width * bit_width + 7) >> 3, align);
    y_size = stride * align_height;
    if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420)) {
        size = (y_size * 3) >> 1;
    } else if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_422) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_422)) {
        size = y_size * 2;
    } else if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_400) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_S8C1) || (buf_attr->pixel_format == OT_PIXEL_FORMAT_U8C1) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_S16C1) || (buf_attr->pixel_format == OT_PIXEL_FORMAT_U16C1) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_S32C1) || (buf_attr->pixel_format == OT_PIXEL_FORMAT_U32C1) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_S64C1) || (buf_attr->pixel_format == OT_PIXEL_FORMAT_U64C1)) {
        size = y_size;
    } else if (buf_attr->pixel_format == OT_PIXEL_FORMAT_UV_420) {
        size = y_size >> 1;
    } else if (ot_common_is_pixel_format_package_422(buf_attr->pixel_format) == TD_TRUE) {
        stride *= 2;
        size = y_size * 2;
    } else {
        size = y_size * 3;
    }

    calc_cfg->vb_size     = size;
    calc_cfg->head_stride = 0;
    calc_cfg->head_size   = 0;
    calc_cfg->head_y_size = 0;
    calc_cfg->main_stride = stride;
    calc_cfg->main_size   = size;
    calc_cfg->main_y_size = y_size;
}

__inline static td_u32 ot_common_get_yuv_head_stride(td_u32 width, ot_compress_mode compress_mode)
{
    if (compress_mode == OT_COMPRESS_MODE_SEG_COMPACT) {
        return 32;
    }
    if (width <= 4096) {
        return 16;
    } else if (width <= 8192) {
        return 32;
    } else {
        return 64;
    }
}

__inline static td_u32 ot_common_get_seg_compress_align_height_chroma(td_u32 align_height,
    ot_pixel_format pixel_format)
{
    if ((pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420) ||
        (pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420)) {
        return (align_height >> 1);
    } else if ((pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_422) ||
        (pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_422)) {
        return align_height;
    } else if (pixel_format == OT_PIXEL_FORMAT_YUV_400) {
        return 0;
    } else {
        return (align_height * 2);
    }
}

__inline static td_void ot_common_get_compact_seg_compress_yuv_buf_cfg(const ot_pic_buf_attr *buf_attr,
    ot_vb_calc_cfg *calc_cfg)
{
    td_u32 align_height, align_c_height, bit_width, head_size, head_y_size, y_size, c_size;
    td_u32 align, head_stride, stride;
    const td_u32 cmp_ratio_luma = OT_SEG_RATIO_8BIT_LUMA;
    const td_u32 cmp_ratio_chroma = OT_SEG_RATIO_8BIT_CHROMA;

    if (calc_cfg == TD_NULL) {
        return;
    }
    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    align_height = OT_ALIGN_UP(buf_attr->height, 2);
    align_c_height = ot_common_get_seg_compress_align_height_chroma(align_height, buf_attr->pixel_format);
    bit_width = ot_common_get_bit_width(buf_attr->bit_width);
    align = ot_common_get_valid_align(buf_attr->align);

    head_stride = ot_common_get_yuv_head_stride(buf_attr->width, buf_attr->compress_mode);
    head_y_size = head_stride * align_height;
    head_size = OT_ALIGN_UP(head_stride * (align_height + align_c_height), align);

    stride = OT_ALIGN_UP(buf_attr->width * bit_width, OT_SEG_WIDTH_BIT_ALIGN);
#ifdef __KERNEL__
    y_size = OT_ALIGN_UP(osal_div64_u64(stride * align_height * 1000ULL, cmp_ratio_luma * 8), align);
    c_size = OT_ALIGN_UP(osal_div64_u64(stride * align_c_height * 1000ULL, cmp_ratio_chroma * 8), align);
#else
    y_size = OT_ALIGN_UP(stride * align_height * 1000ULL / (cmp_ratio_luma * 8), align);
    c_size = OT_ALIGN_UP(stride * align_c_height * 1000ULL / (cmp_ratio_chroma * 8), align);
#endif

    calc_cfg->vb_size     = head_size + y_size + c_size;
    calc_cfg->head_stride = head_stride;
    calc_cfg->head_size   = head_size;
    calc_cfg->head_y_size = head_y_size;
    calc_cfg->main_stride = stride >> 3;
    calc_cfg->main_size   = y_size + c_size;
    calc_cfg->main_y_size = y_size;
}

__inline static td_void ot_common_get_seg_compress_yuv_buf_cfg(const ot_pic_buf_attr *buf_attr,
    ot_vb_calc_cfg *calc_cfg)
{
    td_u32 align_height, bit_width, head_size, head_y_size, size, y_size;
    td_u32 align, head_stride, stride;

    if (calc_cfg == TD_NULL) {
        return;
    }
    if ((buf_attr == TD_NULL) || (buf_attr->width > OT_MAXI_NUM_LIMIT) || (buf_attr->height > OT_MAXI_NUM_LIMIT)) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    align_height = OT_ALIGN_UP(buf_attr->height, 2);
    bit_width = ot_common_get_bit_width(buf_attr->bit_width);
    align = ot_common_get_valid_align(buf_attr->align);

    head_stride = ot_common_get_yuv_head_stride(buf_attr->width, buf_attr->compress_mode);
    head_y_size = head_stride * align_height;
    stride = OT_ALIGN_UP((buf_attr->width * bit_width + 7) >> 3, align);
    y_size = stride * align_height;
    if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420)) {
        head_size = (head_y_size * 3) >> 1;
        size = (y_size * 3) >> 1;
    } else if ((buf_attr->pixel_format == OT_PIXEL_FORMAT_YVU_SEMIPLANAR_422) ||
        (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_SEMIPLANAR_422)) {
        head_size = head_y_size * 2;
        size = y_size * 2;
    } else if (buf_attr->pixel_format == OT_PIXEL_FORMAT_YUV_400) {
        head_size = head_y_size;
        size = y_size;
    } else {
        head_size = head_y_size * 3;
        size = y_size * 3;
    }
    head_size = OT_ALIGN_UP(head_size, align);

    calc_cfg->vb_size     = head_size + size;
    calc_cfg->head_stride = head_stride;
    calc_cfg->head_size   = head_size;
    calc_cfg->head_y_size = head_y_size;
    calc_cfg->main_stride = stride;
    calc_cfg->main_size   = size;
    calc_cfg->main_y_size = y_size;
}

__inline static td_void ot_common_get_yuv_buf_cfg(const ot_pic_buf_attr *buf_attr, ot_vb_calc_cfg *calc_cfg)
{
    if (calc_cfg == TD_NULL) {
        return;
    }
    if (buf_attr == TD_NULL) {
        (td_void)memset_s(calc_cfg, sizeof(*calc_cfg), 0, sizeof(*calc_cfg));
        return;
    }

    if (buf_attr->compress_mode == OT_COMPRESS_MODE_NONE) {
        ot_common_get_uncompressed_yuv_buf_cfg(buf_attr, calc_cfg);
    } else if ((buf_attr->compress_mode == OT_COMPRESS_MODE_SEG_COMPACT) && (buf_attr->width > 256)) {
        /* compact seg compress */
        ot_common_get_compact_seg_compress_yuv_buf_cfg(buf_attr, calc_cfg);
    } else {
        /* seg compress */
        ot_common_get_seg_compress_yuv_buf_cfg(buf_attr, calc_cfg);
    }
}

__inline static td_u32 ot_hnr_width_align(td_u32 size)
{
    td_u32 calc_size;
    const td_u32 shift_offset = 6; /* left offet is 3, right offset is 3 */

    calc_size = OT_ALIGN_UP(size + shift_offset, 32) + 2; /* hnr need align up to 32 */

    return calc_size;
}

__inline static td_u32 ot_hnr_heigh_align(td_u32 size)
{
    td_u32 calc_size;
    const td_u32 shift_offset = 7; /* top offet is 3, bottom offset is 4 */

    /* hnr vb offset: 3 Rows and 4 columns */
    calc_size = OT_ALIGN_UP(size + shift_offset, 32) + 3; /* hnr need align up to 32 */

    return calc_size;
}

__inline static td_u32 ot_aibnr_get_vb_size(td_u32 width, td_u32 height, ot_compress_mode compress_mode)
{
    ot_pic_buf_attr buf_attr = {0};
    ot_vb_calc_cfg calc_cfg = {0};

    buf_attr.width         = ot_hnr_width_align(width);
    buf_attr.height        = ot_hnr_heigh_align(height);
    buf_attr.align         = OT_DEFAULT_ALIGN;
    buf_attr.bit_width     = OT_DATA_BIT_WIDTH_8;
    buf_attr.pixel_format  = OT_PIXEL_FORMAT_RGB_BAYER_12BPP;
    buf_attr.compress_mode = compress_mode;
    buf_attr.video_format  = OT_VIDEO_FORMAT_LINEAR;
    ot_common_get_pic_buf_cfg(&buf_attr, &calc_cfg);

    return calc_cfg.vb_size;
}

__inline static td_u32 ot_aidrc_get_in_vb_size(td_u32 width, td_u32 height, ot_compress_mode compress_mode)
{
    ot_pic_buf_attr buf_attr = {0};
    ot_vb_calc_cfg calc_cfg = {0};

    buf_attr.width         = ot_hnr_width_align(width);
    buf_attr.height        = ot_hnr_heigh_align(height);
    buf_attr.bit_width     = OT_DATA_BIT_WIDTH_8;
    buf_attr.pixel_format  = OT_PIXEL_FORMAT_RGB_BAYER_16BPP;
    buf_attr.compress_mode = compress_mode;
    buf_attr.video_format  = OT_VIDEO_FORMAT_LINEAR;
    ot_common_get_pic_buf_cfg(&buf_attr, &calc_cfg);

    return calc_cfg.vb_size;
}

__inline static td_void ot_aidrc_get_detail_buf_cfg(td_u32 width, td_u32 height, ot_vb_calc_cfg *calc_cfg)
{
    ot_pic_buf_attr buf_attr = {0};

    buf_attr.width         = width;
    buf_attr.height        = height;
    buf_attr.align         = OT_DEFAULT_ALIGN;
    buf_attr.bit_width     = OT_DATA_BIT_WIDTH_8;
    buf_attr.pixel_format  = OT_PIXEL_FORMAT_RGB_BAYER_8BPP;
    buf_attr.compress_mode = OT_COMPRESS_MODE_NONE;
    buf_attr.video_format  = OT_VIDEO_FORMAT_LINEAR;

    ot_common_get_pic_buf_cfg(&buf_attr, calc_cfg);
}

__inline static td_u32 ot_aidrc_get_coef_buf_size(td_u32 width, td_u32 height)
{
    td_u32 coef_size, coef_min_size;
    const td_u32 down_sample_factor = 32;
    const td_u32 channels = 112;

    coef_size = OT_DIV_UP(width, down_sample_factor) * OT_DIV_UP(height, down_sample_factor) * channels;
    coef_min_size = 60 * 34 * channels; /* min size: 60 x 34 */

    return MAX2(coef_size, coef_min_size);
}

__inline static td_u32 ot_ai3dnr_get_vb_size(td_u32 width, td_u32 height, ot_compress_mode compress_mode)
{
    ot_pic_buf_attr buf_attr = {0};
    ot_vb_calc_cfg calc_cfg = {0};

    buf_attr.width         = OT_ALIGN_UP(width + 64, 16); /* add 64 for overlap; align up to 16 */
    buf_attr.height        = OT_ALIGN_UP(height, 16); /* align up to 16 */
    buf_attr.align         = 0;
    buf_attr.bit_width     = OT_DATA_BIT_WIDTH_8;
    buf_attr.pixel_format  = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
    buf_attr.compress_mode = compress_mode;
    buf_attr.video_format  = OT_VIDEO_FORMAT_LINEAR;
    ot_common_get_pic_buf_cfg(&buf_attr, &calc_cfg);

    return calc_cfg.vb_size;
}

__inline static td_bool ot_vdec_check_pic_size(ot_payload_type type, td_u32 width, td_u32 height)
{
    if ((type == OT_PT_H265) && (width <= OT_H265D_MAX_WIDTH) && (height <= OT_H265D_MAX_HEIGHT)) {
        return TD_TRUE;
    }
    if ((type == OT_PT_H264) && (width <= OT_H264D_MAX_WIDTH) && (height <= OT_H264D_MAX_HEIGHT)) {
        return TD_TRUE;
    }
    if ((type == OT_PT_JPEG || type == OT_PT_MJPEG) &&
        (width <= OT_JPEGD_MAX_WIDTH) && (height <= OT_JPEGD_MAX_HEIGHT)) {
        return TD_TRUE;
    }
    return TD_FALSE;
}

__inline static td_bool ot_venc_check_pic_buf_size(ot_payload_type type, const ot_venc_buf_attr *attr)
{
    if (type != OT_PT_H264 && type != OT_PT_H265) {
        return TD_FALSE;
    }

    if (attr == NULL) {
        return TD_FALSE;
    }

    if (attr->share_buf_en != TD_FALSE && attr->share_buf_en != TD_TRUE) {
        return TD_FALSE;
    }

    if (attr->frame_buf_ratio < 70 || attr->frame_buf_ratio > 100) {
        return TD_FALSE;
    }

    if (type == OT_PT_H264 &&
        (attr->pic_buf_attr.width > OT_VENC_H264_MAX_WIDTH || attr->pic_buf_attr.height > OT_VENC_H264_MAX_HEIGHT)) {
        return TD_FALSE;
    }

    if (type == OT_PT_H265 &&
        (attr->pic_buf_attr.width > OT_VENC_H265_MAX_WIDTH || attr->pic_buf_attr.height > OT_VENC_H265_MAX_HEIGHT)) {
        return TD_FALSE;
    }

    if (attr->pic_buf_attr.bit_width != OT_DATA_BIT_WIDTH_8) {
        return TD_FALSE;
    }

    return TD_TRUE;
}

__inline static td_u32 ot_venc_get_h264_pic_buf_size(ot_payload_type type, const ot_venc_buf_attr *attr)
{
    td_u32 y_header_stride, c_header_stride;
    td_u32 y_header_size, c_header_size;
    td_u32 y_size, c_size;
    td_u32 blk_height_y, blk_height_c;
    td_u32 width, height;
    td_bool share_buf;
    td_u32 frame_buf_ratio;
    td_u32 pic_size;

    width = attr->pic_buf_attr.width;
    height = attr->pic_buf_attr.height;
    share_buf = attr->share_buf_en;
    frame_buf_ratio = attr->frame_buf_ratio;

    if (width <= 2048) {
        y_header_stride = 128;
    } else if (width <= 4096) {
        y_header_stride = 256;
    } else if (width <= 6144) {
        y_header_stride = 384;
    } else {
        y_header_stride = 512;
    }

    c_header_stride = y_header_stride;

    y_header_size = y_header_stride * (OT_ALIGN_UP(height, 16) / 16);
    c_header_size = c_header_stride * (OT_ALIGN_UP(height, 16) / 16);

    if (share_buf == TD_FALSE) {
        blk_height_y = 0;
        blk_height_c = 0;
    } else {
        blk_height_y = ((16 * 4 + 16 + 16 + 15) / 16) * 16;
        blk_height_c = blk_height_y / 2;
    }

    y_size = OT_ALIGN_UP(width * (height + blk_height_y) * frame_buf_ratio / 100, 256);
    c_size = OT_ALIGN_UP(width * (height / 2 + blk_height_c) * frame_buf_ratio / 100, 256);

    if (share_buf == TD_FALSE) {
        pic_size = y_header_size + c_header_size + y_size + c_size;
    } else {
        pic_size = (y_header_size + c_header_size) * 2 + y_size + c_size;
    }

    return pic_size;
}

__inline static td_u32 ot_venc_get_h265_pic_buf_size(ot_payload_type type, const ot_venc_buf_attr *attr)
{
    td_u32 y_header_stride, c_header_stride;
    td_u32 y_header_size, c_header_size;
    td_u32 y_size, c_size;
    td_u32 blk_height_y, blk_height_c;
    td_u32 width, height;
    td_bool share_buf;
    td_u32 frame_buf_ratio;
    td_u32 pic_size;

    width = attr->pic_buf_attr.width;
    height = attr->pic_buf_attr.height;
    share_buf = attr->share_buf_en;
    frame_buf_ratio = attr->frame_buf_ratio;

    if (width <= 2048) {
        y_header_stride = 256;
    } else if (width <= 4096) {
        y_header_stride = 512;
    } else if (width <= 6144) {
        y_header_stride = 768;
    } else {
        y_header_stride = 1024;
    }

    c_header_stride = y_header_stride / 2;

    y_header_size = y_header_stride * (OT_ALIGN_UP(height, 32) / 32);
    c_header_size = c_header_stride * (OT_ALIGN_UP(height, 32) / 32);

    if (share_buf == TD_FALSE) {
        blk_height_y = 0;
        blk_height_c = 0;
    } else {
        blk_height_y = ((28 * 4 + 16 + 32 + 15) / 16) * 16;
        blk_height_c = blk_height_y / 2;
    }

    y_size = OT_ALIGN_UP(width * (height + blk_height_y) * frame_buf_ratio / 100, 256);
    c_size = OT_ALIGN_UP(width * (height / 2 + blk_height_c) * frame_buf_ratio / 100, 256);

    if (share_buf == TD_FALSE) {
        pic_size = y_header_size + c_header_size + y_size + c_size;
    } else {
        pic_size = (y_header_size + c_header_size) * 2 + y_size + c_size;
    }

    return pic_size;
}

__inline static td_bool ot_venc_is_mosaic_blk_valid(td_u32 blk_size)
{
    if (blk_size == 4 || blk_size == 8 || blk_size == 16 || // 4, 8, 16: blk size
        blk_size == 32 || blk_size == 64 || blk_size == 128) { // 32, 64, 128: blk size
        return TD_TRUE;
    }

    return TD_FALSE;
}

__inline static td_void ot_common_get_fmu_align_size(td_u32 *width, td_u32 *height)
{
    *height = OT_ALIGN_UP(*height, 4); /* 4: height align */
    *width = OT_ALIGN_UP(*width, OT_DEFAULT_ALIGN);
}

__inline static td_u32 ot_vi_get_fmu_wrap_page_num(td_u32 width, td_u32 height)
{
    const td_u32 page_size = 0x8000; /* 0x8000, page_size */
    td_u32 total_size;
    td_u32 page_num;

    ot_common_get_fmu_align_size(&width, &height);

    total_size = width * ((height >> 1) + OT_FMU_MIN_BUF_LINE);
    page_num = OT_ALIGN_UP(total_size, page_size) / page_size + 2; /* 2: ext */

    page_num = clip3(page_num, OT_FMU_MIN_PAGE_NUM, OT_FMU_MAX_Y_PAGE_NUM);

    return page_num;
}

__inline static td_u32 ot_vpss_get_fmu_wrap_page_num(td_u32 width, td_u32 height)
{
    const td_u32 page_size = 0x8000; /* 0x8000, page_size */
    td_u32 y_size, c_size;
    td_u32 y_page_num, c_page_num;

    ot_common_get_fmu_align_size(&width, &height);

    y_size = width * (OT_FMU_MIN_BUF_LINE << 2); /* 2: pre */
    c_size = y_size >> 1;
    y_page_num = OT_ALIGN_UP(y_size, page_size) / page_size + 3; /* 3: ext */
    c_page_num = OT_ALIGN_UP(c_size, page_size) / page_size + 3; /* 3: ext */
    y_page_num = clip3(y_page_num, OT_FMU_MIN_PAGE_NUM, OT_FMU_MAX_Y_PAGE_NUM);
    c_page_num = clip3(c_page_num, OT_FMU_MIN_PAGE_NUM, OT_FMU_MAX_C_PAGE_NUM);

    return y_page_num + c_page_num;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* OT_BUFFER_DETAIL_H */
